home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
m2
/
cat3src
/
cat
/
catfiles.i
< prev
next >
Wrap
Text File
|
1997-10-26
|
19KB
|
640 lines
IMPLEMENTATION MODULE CatFiles;
FROM SYSTEM IMPORT ADDRESS, ADR, CAST, ASSEMBLER;
FROM Void IMPORT v;
IMPORT Strings;
IMPORT mtAlerts;
IMPORT MagicDOS;
IMPORT MagicSys;
IMPORT MagicStrings;
IMPORT CatTypes;
IMPORT CatGlobal;
IMPORT WildCards;
IMPORT Mintbind;
IMPORT FileSys;
IMPORT MTE;
(* ErrorAlert neu implementiert. Diese Implementation spart > 2 kB Speicher ein!
*)
(*$L-*)
PROCEDURE errorMessages ();
BEGIN
ASSEMBLER
DC.W MagicDOS.Error
ACZ 'Gemdos-Fehler'
SYNC
DC.W MagicDOS.EDrvNR
ACZ 'Unbekanntes Laufwerk'
SYNC
DC.W MagicDOS.EUnCmd
ACZ 'Unbekannter Befehl'
SYNC
DC.W MagicDOS.ECRC
ACZ 'CRC Fehler'
SYNC
DC.W MagicDOS.EBadRq
ACZ 'Inkorrekte Anforderung'
SYNC
DC.W MagicDOS.ESeek
ACZ 'Seek Fehler'
SYNC
DC.W MagicDOS.EMedia
ACZ 'Unbekanntes Medium'
SYNC
DC.W MagicDOS.ESecNF
ACZ 'Sektor nicht gefunden'
SYNC
DC.W MagicDOS.EPaper
ACZ 'Kein Papier'
SYNC
DC.W MagicDOS.EWritF
ACZ 'Schreibfehler'
SYNC
DC.W MagicDOS.EReadF
ACZ 'Lesefehler'
SYNC
DC.W MagicDOS.EGenrl
ACZ 'Allgemeiner Fehler'
SYNC
DC.W MagicDOS.EWrPro
ACZ 'Schreibgeschtzt'
SYNC
DC.W MagicDOS.EChng
ACZ 'Medium gewechselt'
SYNC
DC.W MagicDOS.EUnDev
ACZ 'Unbekanntes Laufwerk'
SYNC
DC.W MagicDOS.EBadSF
ACZ 'Defekte Sektoren'
SYNC
DC.W MagicDOS.EOther
ACZ 'Andere Disk einlegen'
SYNC
DC.W MagicDOS.EInvFN
ACZ 'Ungltige GEMDOS-Funktion'
SYNC
DC.W MagicDOS.EFilNF
ACZ 'Datei nicht gefunden'
SYNC
DC.W MagicDOS.EPthNF
ACZ 'Pfad nicht gefunden'
SYNC
DC.W MagicDOS.ENHndl
ACZ 'GEMDOS hat keine|Dateihandles mehr'
SYNC
DC.W MagicDOS.EAccDn
ACZ 'Zugriff nicht mglich'
SYNC
DC.W MagicDOS.EIHndl
ACZ 'Ungltiges Handle'
SYNC
DC.W MagicDOS.ENSMem
ACZ 'Unzureichender Speicher'
SYNC
DC.W MagicDOS.EIMBA
ACZ 'Ungltige Speicherblockadresse'
SYNC
DC.W MagicDOS.EIMBA
ACZ 'Ungltige Speicherblockadresse'
SYNC
DC.W MagicDOS.EDrive
ACZ 'Ungltiges Laufwerk'
SYNC
DC.W MagicDOS.ENMFil
ACZ 'Keine weiteren Dateien'
SYNC
(* Netzwerk-Fehlercodes *)
DC.W (* MagicDOS.ELOCKED *) -58
ACZ 'File ist fr anderes|Programm reserviert. Zugriff|momentan nicht mglich.'
SYNC
DC.W (* MagicDOS.ENSLOCK *) -59
ACZ 'Unlocking nicht mglich.|(Falsche Recordangaben)'
SYNC
DC.W MagicDOS.ERange
ACZ 'Bereichsberschreitung'
SYNC
DC.W MagicDOS.EIntrn
ACZ 'Interner Fehler'
SYNC
DC.W MagicDOS.EPLFmt
ACZ 'Ungltiges Programmladeformat'
SYNC
DC.W MagicDOS.EGSBF
ACZ 'Setblock failure due|to growth restriction'
SYNC
(*
DC.W BuffUsed
ACZ 'Interner Puffer belegt'
SYNC
DC.W BuffNotUsed
ACZ 'Interner Puffer leer'
SYNC
DC.W FileEmpty
ACZ 'Leere Datei'
SYNC
DC.W EOF
ACZ 'berraschendes Fileende'
SYNC
*)
DC.W notAllWritten
ACZ 'Nicht alle|Daten geschrieben.|Evtl. Platte voll?'
SYNC
DC.W notAllRead
ACZ 'Ein Lesefehler ist aufgetreten,|es wurden nicht alle|Daten gelesen.'
SYNC
DC.W crcError
ACZ 'CRC-Fehler in der|Datenbank.'
SYNC
; Endemarke:
DC.L 0
END;
END errorMessages;
(*$L=*)
PROCEDURE GetErrorMsg (nr: INTEGER; VAR str: ARRAY OF CHAR);
VAR adr : CatTypes.Str255Ptr;
BEGIN
(* Erstmal in errorMessages nach der Nummer suchen und dann
* ber die Stringadresse zuweisen
*)
adr := NIL;
(* Ginge auch in M2, aber so ist es einfacher :-)) *)
ASSEMBLER
LEA errorMessages,A0
MOVE.W nr(A6),D0
check:
MOVE.W (A0)+,D1
CMP.W D0,D1
BEQ.S found
; Jetzt Bytes skippen, bis wir ein 0-Byte gefunden haben
skip:
TST.B (A0)+
BNE.S skip
; Adresse testen, ob sie gerade ist
MOVE.L A0,D1
BTST #0,D1
BEQ.S noAdd
; Ungerade Adresse, 1 draufaddieren
ADDQ.L #1,D1
MOVEA.L D1,A0
noAdd:
; test auf Endemarke
TST.L (A0)
BNE.S check
BRA.S nfound
found:
MOVE.L A0,adr(A6)
nfound:
END;
IF adr # NIL
THEN
MagicStrings.Assign (adr^, str);
IF (nr < 0) & (nr > -100)
THEN
MagicStrings.Append ('|GemDos &', str);
END;
ELSE
MagicStrings.Assign ('Unbekannter Fehler!|GemDos &', str);
END;
END GetErrorMsg;
PROCEDURE ErrorAlert(nr : INTEGER);
VAR alt : CatTypes.String255;
BEGIN
(* Fehlermeldung holen *)
IF nr = MagicDOS.EOK THEN RETURN
ELSE
GetErrorMsg (nr, alt);
(* Anfang vom Alert *)
MagicStrings.Insert ('[3][|', alt, 0);
(* Ende vom Alert *)
MagicStrings.Append ('][[Abbruch]', alt);
MTE.numAlert(nr, alt);
END;
(*
(* Soll Mal fr alle Fehlermeldungen zustndig sein *)
IF nr = MagicDOS.EOK THEN RETURN
ELSIF nr = MagicDOS.Error THEN
v.int := mtAlerts.Alert(1, '[3][|Gemdos-Fehler|GemDos -1][[Abbruch]');
ELSIF nr = MagicDOS.EDrvNR THEN
v.int := mtAlerts.Alert(1, '[3][|Unbekanntes Laufwerk|GemDos -2][[Abbruch]');
ELSIF nr = MagicDOS.EUnCmd THEN
v.int := mtAlerts.Alert(1, '[3][|Unbekannter Befehl|GemDos -3][[Abbruch]');
ELSIF nr = MagicDOS.ECRC THEN
v.int := mtAlerts.Alert(1, '[3][|CRC Fehler|GemDos -4][[Abbruch]');
ELSIF nr = MagicDOS.EBadRq THEN
v.int := mtAlerts.Alert(1, '[3][|Inkorrekte Anforderung|GemDos -5][[Abbruch]');
ELSIF nr = MagicDOS.ESeek THEN
v.int := mtAlerts.Alert(1, '[3][|Seek Fehler|GemDos -6][[Abbruch]');
ELSIF nr = MagicDOS.EMedia THEN
v.int := mtAlerts.Alert(1, '[3][|Unbekanntes Medium|GemDos -7][[Abbruch]');
ELSIF nr = MagicDOS.ESecNF THEN
v.int := mtAlerts.Alert(1, '[3][|Sektor nicht gefunden|GemDos -8][[Abbruch]');
ELSIF nr = MagicDOS.EPaper THEN
v.int := mtAlerts.Alert(1, '[3][|Kein Papier|GemDos -9][[Abbruch]');
ELSIF nr = MagicDOS.EWritF THEN
v.int := mtAlerts.Alert(1, '[3][|Schreibfehler|GemDos -10][[Abbruch]');
ELSIF nr = MagicDOS.EReadF THEN
v.int := mtAlerts.Alert(1, '[3][|Lesefehler|GemDos -11][[Abbruch]');
ELSIF nr = MagicDOS.EGenrl THEN
v.int := mtAlerts.Alert(1, '[3][|Allgemeiner Fehler|GemDos -12][[Abbruch]');
ELSIF nr = MagicDOS.EWrPro THEN
v.int := mtAlerts.Alert(1, '[3][|Schreibgeschtzt|GemDos -13][[Abbruch]');
ELSIF nr = MagicDOS.EChng THEN
v.int := mtAlerts.Alert(1, '[3][|Medium gewechselt|GemDos -14][[Abbruch]');
ELSIF nr = MagicDOS.EUnDev THEN
v.int := mtAlerts.Alert(1, '[3][|Unbekanntes Laufwerk|GemDos -15][[Abbruch]');
ELSIF nr = MagicDOS.EBadSF THEN
v.int := mtAlerts.Alert(1, '[3][|Defekte Sektoren|GemDos -16][[Abbruch]');
ELSIF nr = MagicDOS.EOther THEN
v.int := mtAlerts.Alert(1, '[3][|Andere Disk einlegen|GemDos -17][[Abbruch]');
ELSIF nr = MagicDOS.EInvFN THEN
v.int := mtAlerts.Alert(1, '[3][|Falsche Funktionsnummer|GemDos -32][[Abbruch]');
ELSIF nr = MagicDOS.EFilNF THEN
v.int := mtAlerts.Alert(1, '[3][|Datei nicht gefunden|GemDos -33][[Abbruch]');
ELSIF nr = MagicDOS.EPthNF THEN
v.int := mtAlerts.Alert(1, '[3][|Pfad nicht gefunden|GemDos -34][[Abbruch]');
ELSIF nr = MagicDOS.ENHndl THEN
v.int := mtAlerts.Alert(1, '[3][|GEMDOS hat keine|Dateihandles mehr|GemDos -35][[Abbruch]');
ELSIF nr = MagicDOS.EAccDn THEN
v.int := mtAlerts.Alert(1, '[3][|Zugriff nicht mglich|GemDos -36][[Abbruch]');
ELSIF nr = MagicDOS.EIHndl THEN
v.int := mtAlerts.Alert(1, '[3][|Ungltiges Handle|GemDos -37][[Abbruch]');
ELSIF nr = MagicDOS.ENSMem THEN
v.int := mtAlerts.Alert(1, '[3][|Unzureichender Speicher|GemDos -39][[Abbruch]');
ELSIF nr = MagicDOS.EIMBA THEN
v.int := mtAlerts.Alert(1, '[3][|Ungltige Speicherblockadresse|GemDos -40][[Abbruch]');
ELSIF nr = MagicDOS.EIMBA THEN
v.int := mtAlerts.Alert(1, '[3][|Ungltige Speicherblockadresse|GemDos -40][[Abbruch]');
ELSIF nr = MagicDOS.EDrive THEN
v.int := mtAlerts.Alert(1, '[3][|Ungltiges Laufwerk|GemDos -46][[Abbruch]');
ELSIF nr = MagicDOS.ENMFil THEN
v.int := mtAlerts.Alert(1, '[3][|Keine weiteren Dateien|GemDos -49][[Abbruch]');
(* Netzwerk-Fehlercodes *)
ELSIF nr = (* MagicDOS.ELOCKED *) -58 THEN
v.int := mtAlerts.Alert (1, '[3][|File ist fr anderes|Programm reserviert. Zugriff|momentan nicht mglich.|GemDos -58][[Abbruch]');
ELSIF nr = (* MagicDOS.ENSLOCK *) -59 THEN
v.int := mtAlerts.Alert (1, '[3][|Unlocking nicht mglich.|(Falsche Recordangaben)|GemDos - 59][[Abbruch]');
ELSIF nr = MagicDOS.ERange THEN
v.int := mtAlerts.Alert(1, '[3][|Bereichsberschreitung|GemDos -64][[Abbruch]');
ELSIF nr = MagicDOS.EIntrn THEN
v.int := mtAlerts.Alert(1, '[3][|Interner Fehler|GemDos -65][[Abbruch]');
ELSIF nr = MagicDOS.EPLFmt THEN
v.int := mtAlerts.Alert(1, '[3][|Ungltiges Programmladeformat|GemDos -66][[Abbruch]');
ELSIF nr = MagicDOS.EGSBF THEN
v.int := mtAlerts.Alert(1, '[3][|Setblock failure due|to growth restriction|GemDos -67][[Abbruch]');
(*
ELSIF nr = BuffUsed THEN
v.int := mtAlerts.Alert(1, '[3][|Interner Puffer belegt][[Abbruch]');
ELSIF nr = BuffNotUsed THEN
v.int := mtAlerts.Alert(1, '[3][|Interner Puffer leer][[Abbruch]');
ELSIF nr = FileEmpty THEN
v.int := mtAlerts.Alert(1, '[3][|Leere Datei][[Abbruch]');
ELSIF nr = EOF THEN
v.int := mtAlerts.Alert(1, '[3][|berraschendes Fileende][[Abbruch]');
*)
ELSIF nr = notAllWritten THEN
v.int := mtAlerts.Alert(1, '[3][|Nicht alle|Daten geschrieben.|Evtl. Platte voll?][[Abbruch]');
ELSIF nr = notAllRead THEN
v.int := mtAlerts.Alert(1, '[3][|Ein Lesefehler ist aufgetreten,|es wurden nicht alle|Daten gelesen.][[Abbruch]');
ELSIF nr = crcError THEN
v.int := mtAlerts.Alert(1, '[3][|CRC-Fehler in der|Datenbank.][[Abbruch]');
ELSE
MTE.numAlert(nr, '[3][|Unbekannter Fehler|GemDos &][[Abbruch]');
END;
*)
END ErrorAlert;
(*
PROCEDURE stopSearch():BOOLEAN;
VAR dum : LONGCARD;
BEGIN
IF MagicDOS.Cconis() THEN
dum := MagicDOS.Crawin();
RETURN SHORT(dum) = 32 (* esc char *)
ELSE
RETURN FALSE
END;
END stopSearch;
*)
PROCEDURE OpenFile(REF path, name : ARRAY OF CHAR; mode : openMode):INTEGER;
VAR handle : INTEGER;
MODE : BITSET;
file : CatTypes.String255;
BEGIN
FileError := NoError;
CASE mode OF
readFile : MODE := BITSET(MagicDOS.Read)|
writeFile : MODE := {0}|
readWrite : MODE := {1}; |
END;
MagicStrings.Assign(path, file);
MagicStrings.Append(name, file);
handle := MagicDOS.Fopen(file, MODE);
IF (handle = MagicDOS.EFilNF) & (mode # readFile) THEN
handle := MagicDOS.Fcreate(file, {});
IF mode = readWrite
THEN
FileError := MagicDOS.Fclose(handle);
handle := MagicDOS.Fopen(file, MODE);
END;
END;
IF handle < 0 THEN
FileError := handle
ELSE
FileError := NoError;
END;
RETURN handle
END OpenFile;
PROCEDURE CreateFile(REF path, name : ARRAY OF CHAR):INTEGER;
VAR handle : INTEGER;
file : CatTypes.String255;
BEGIN
FileError := NoError;
MagicStrings.Assign(path, file);
MagicStrings.Append(name, file);
handle := MagicDOS.Fcreate(file, {});
IF handle < 0 THEN FileError := handle END;
RETURN handle
END CreateFile;
PROCEDURE WriteFile(c : CHAR; handle : INTEGER);
VAR count : LONGCARD;
BEGIN
FileError := NoError;
count := 1;
MagicDOS.Fwrite(handle, count, ADR(c));
IF LONGINT(count) < 0 THEN
FileError := CAST(INTEGER,count)
ELSIF count # 1 THEN
FileError := notAllWritten;
END;
END WriteFile;
PROCEDURE WriteMuch(howMuch : LONGCARD; handle : INTEGER; where : ADDRESS);
VAR count : LONGCARD;
BEGIN
(* IF stopSearch() THEN FileError := MagicDOS.EWritF; RETURN END; *)
FileError := NoError;
count := howMuch;
MagicDOS.Fwrite(handle, count, where);
IF LONGINT(count) < 0 THEN
FileError := CAST(INTEGER,count)
ELSIF count # howMuch THEN
FileError := notAllWritten;
END
END WriteMuch;
PROCEDURE ReadFile(VAR c : CHAR; handle : INTEGER);
VAR count : LONGCARD;
BEGIN
FileError := NoError;
count := 1;
MagicDOS.Fread(handle, count, ADR(c));
IF LONGINT(count) < 0 THEN
FileError := CAST(INTEGER,count)
ELSIF count # 1 THEN
FileError := notAllRead;
END;
END ReadFile;
PROCEDURE ReadMuch(howMuch : LONGCARD; handle : INTEGER; where : ADDRESS);
VAR count : LONGCARD;
BEGIN
(* IF stopSearch() THEN FileError := MagicDOS.EReadF; RETURN END; *)
FileError := NoError;
count := howMuch;
MagicDOS.Fread(handle, count, where);
IF LONGINT(count) < 0 THEN
FileError := CAST(INTEGER,count)
ELSIF count # howMuch THEN
FileError := notAllRead;
END;
END ReadMuch;
PROCEDURE FilePos(handle : INTEGER):LONGCARD;
VAR pos : LONGCARD;
BEGIN
FileError := NoError;
pos := MagicDOS.Fseek(0, handle, MagicDOS.SeekPos);
IF LONGINT(pos) < 0 THEN FileError := CAST(INTEGER,pos) END;
RETURN pos
END FilePos;
PROCEDURE Seek(pos : LONGINT; handle : INTEGER; what : SeekMode);
VAR err : LONGCARD;
BEGIN
FileError := NoError;
CASE what OF
start : err := MagicDOS.Fseek(pos, handle, MagicDOS.SeekStart)|
relative : err := MagicDOS.Fseek(pos, handle, MagicDOS.SeekPos)|
end : err := MagicDOS.Fseek(pos, handle, MagicDOS.SeekEnd)|
END;
(* Hier fragt sowieso keiner, auerdem ist mir nicht klar, wie man unterscheiden kann,
ob ein Fehler im unteren Wort steht, ohne da es zu Fehlinterpretationen kommen kann.
Was ist mit Seek auf CARDINAL(-37), das ist doch ohne weiteres Mglich.. grr
IF err < 0 THEN FileError := CAST(INTEGER,pos) END;
*)
END Seek;
PROCEDURE CloseFile(handle : INTEGER);
BEGIN
FileError := MagicDOS.Fclose(handle);
END CloseFile;
PROCEDURE SetPath(REF path : ARRAY OF CHAR):BOOLEAN;
VAR drv : CHAR;
BEGIN
IF path[1] = ':' THEN
drv := CAP(path[0]);
MagicDOS.Dsetdrv(ORD(drv)-ORD('A'), v.lbset)
END;
RETURN MagicDOS.Dsetpath(path) = 0
END SetPath;
PROCEDURE GetPath(VAR path : ARRAY OF CHAR);
VAR drive : CARDINAL;
BEGIN
drive := MagicDOS.Dgetdrv();
MagicDOS.Dgetpath (path, drive+1);
MagicStrings.Insert ('A:', path, 0);
MagicStrings.Append ('\', path);
path[0] := CHR(ORD('A')+drive);
END GetPath;
PROCEDURE ClearPath(REF path, mask, lock : ARRAY OF CHAR);
TYPE DTAType = RECORD res : ARRAY[0..29] OF CHAR; name : ARRAY[0..13] OF CHAR END;
VAR DTAPtr : POINTER TO DTAType;
notAll : BOOLEAN;
tmp,
readmask : CatTypes.String1023;
toLower : BOOLEAN;
firstFound : BOOLEAN;
dHandle : LONGINT;
nPtr : CatTypes.Str1023Ptr;
xattr : FileSys.XATTR;
err : LONGINT;
BEGIN
IF ~CatGlobal.isMintDomain
THEN
IF SetPath(path) THEN
DTAPtr := ADDRESS(MagicDOS.Fgetdta());
IF MagicDOS.Fsfirst (mask, {}) >= 0 THEN
REPEAT
IF ~MagicStrings.Equal(DTAPtr^.name, lock) THEN
IF ~MagicDOS.Fdelete(DTAPtr^.name) THEN
ErrorAlert(MagicDOS.EAccDn)
END;
END;
UNTIL MagicDOS.Fsnext() < 0;
END;
ELSE
ErrorAlert(MagicDOS.EPthNF)
END;
ELSE
dHandle := Mintbind.Dopendir (path, 0);
IF dHandle >= 0
THEN
nPtr := ADR (readmask[4]);
firstFound := TRUE;
toLower := TRUE;
REPEAT
err := Mintbind.Dreaddir (dHandle, readmask);
IF err = 0
THEN
IF firstFound
THEN
(* Get attributes of file, follow link *)
MagicStrings.Assign (path, tmp);
MagicStrings.Append (nPtr^, tmp);
toLower := 0 # (Mintbind.Dpathconf (tmp, 6));
firstFound := FALSE;
END;
IF toLower
THEN
Strings.Lower (nPtr^);
(*$W-*)
Strings.Lower (mask);
Strings.Lower (lock);
(*$W=*)
END;
(* Compare name, in den ersten 4 Bytes steht der inode *)
IF WildCards.NameMatching (nPtr^, mask)
THEN
IF ~WildCards.NameMatching (nPtr^, lock)
THEN
MagicStrings.Assign (path, tmp);
MagicStrings.Append (nPtr^, tmp);
IF ~MagicDOS.Fdelete(tmp) THEN
ErrorAlert(MagicDOS.EAccDn)
END;
END;
END;
END;
UNTIL err # 0;
IF (err # MagicDOS.ENMFil)
& (err # MagicDOS.EFilNF)
THEN
ErrorAlert (SHORT (err));
END;
v.lint := Mintbind.Dclosedir (dHandle);
ELSE
ErrorAlert(MagicDOS.EPthNF)
END;
END;
END ClearPath;
PROCEDURE DeleteFile(REF path, name : ARRAY OF CHAR):BOOLEAN;
VAR file : CatTypes.String255;
BEGIN
MagicStrings.Assign(path, file);
MagicStrings.Append(name, file);
RETURN MagicDOS.Fdelete(file)
END DeleteFile;
PROCEDURE RenameFile(REF path, name, path2, name2 : ARRAY OF CHAR):BOOLEAN;
VAR file : CatTypes.String255;
BEGIN
IF SetPath(path) THEN
MagicStrings.Assign(path2, file);
MagicStrings.Append(name2, file);
(*$W-*)
RETURN MagicDOS.Frename(name, file) > 0
(*$W=*)
ELSE
RETURN FALSE
END;
END RenameFile;
PROCEDURE FileSizeAndDate (REF fname : ARRAY OF CHAR; VAR exists: BOOLEAN;
VAR date, time: CARDINAL) : LONGCARD;
VAR oDta: ADDRESS;
dta : MagicDOS.DTA;
res : INTEGER;
err : LONGINT;
xattr : FileSys.XATTR;
BEGIN
IF ~CatGlobal.isMintDomain
THEN
oDta := MagicDOS.Fgetdta ();
MagicDOS.Fsetdta (ADR(dta));
res := MagicDOS.Fsfirst (fname, {});
MagicDOS.Fsetdta (oDta);
exists := res = 0;
IF res # 0 THEN RETURN 0 END;
date := dta.dDate;
time := dta.dTime;
RETURN dta.dLength;
ELSE
err := Mintbind.Fxattr (0, fname, xattr);
IF err = 0
THEN
exists := TRUE;
date := CARDINAL(xattr.mdate);
time := CARDINAL(xattr.mtime);
RETURN LONGCARD(xattr.size);
END;
exists := FALSE;
RETURN 0;
END;
END FileSizeAndDate;
PROCEDURE FileSize (REF fname : ARRAY OF CHAR; VAR exists: BOOLEAN) : LONGCARD;
BEGIN
RETURN FileSizeAndDate (fname, exists, v.card, v.card);
END FileSize;
PROCEDURE Exists (REF fname: ARRAY OF CHAR): BOOLEAN;
VAR bla : LONGCARD;
res : BOOLEAN;
BEGIN
bla := FileSize (fname, res);
RETURN res;
END Exists;
END CatFiles.